import { ProxyOb } from './ProxyOb';
/*
 * @features: VM核心
 * @description: watchPath 的基础，只提供绑定功能 和 对应的数据更新函数
 * @Date: 2021-09-06 11:47:17
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2021-09-11 18:44:41
 * @LastEditors: judu233
 */

const { ccclass, property, executeInEditMode, disallowMultiple, menu } = cc._decorator;

/**自动检查识别的数组,你可以准备自己的组件放上去自动识别 */
const COMP_ARRAY_CHECK = [
    //组件名、默认属性、controller值
    ['cc.Label', 'string', false],
    ['cc.RichText', 'string', false],
    ['cc.EditBox', 'string', true],
    ['cc.Slider', 'progress', true],
    ['cc.ProgressBar', 'progress', false],
    ['cc.Toggle', 'isChecked', true],
    [`VmSprite`, `index`, true],
    [`VmPage`, `index`, true],
    ['BhvRollNumber', 'targetValue', false],
];

/**限制值边界范围的模式 */
enum CLAMP_MODE { MIN, MAX, MIN_MAX, }
/**快速操作 */
enum ACTION_MODE { 查找组件, 激活组件, 替换组件, 删除组件 };
/**查找列表 */
enum FIND_LIST { VmBase, VmParent, VmLabel, VmProgress, VmState, }

// +普通 label 更新数据的情况,label.string = xxx;
// +frameIndex 插件，通过number 数值设置 BhvFrameIndex 来切换当前贴图
// +spriteFrame 直接替换贴图的情况 , 
//  读取本地路径 data.spriteFrame = $res:/pic/com1
//  读取网页路径 data.spriteFrame = $url:http:xxxxxxxxxx.png
// +特殊条件控制 

// 比较条件:,如果传入值 > /< />= /<= /== 某值时，执行的action类型


// enum WatchMode {
//     ccLabel,
//     ccRichText,
//     ccSlider,
//     ccProgressBar,
// }

enum FILTER_MODE {
    "none",
    "==", //正常计算，比较 等于
    "!=", //正常计算，比较 不等于
    ">",  //正常计算，比较>
    ">=", //正常计算，比较>=
    "<",  //正常计算，比较<
    "<=", // 正常计算，比较>=
}

/**
 * 可以继承重写
 */
@ccclass("EventHandleCall")
export class EventHandleCall {
    @property({ type: cc.Component.EventHandler, tooltip: "回调列表", displayName: "回调" })
    compEvents: cc.Component.EventHandler[] = [];

    @property({ type: [cc.Node], displayName: `开启节点列表` })
    openActiveList: cc.Node[] = [];

    @property({ type: [cc.Node], displayName: `关闭节点列表` })
    closeActiveList: cc.Node[] = [];

    /**
     * 派发ccEventHandler事件
     * @param values 参数
     */
    call(values: any[]) {
        this.close();
        this.open();
        this.emitEvent(values);
    }

    close() {
        this.closeActiveList.forEach(node => node && (node.active = false));
    }
    open() {
        this.openActiveList.forEach(node => node && (node.active = true));
    }
    emitEvent(...values: any[]) {
        if (this.compEvents.length == 0) {
            // console.warn(`EventHandleCall没有事件需要回调`, this);
            return;
        }
        /**默认的 EventHandler 的参数是在最后一个 翻转一下 */
        for (let event of this.compEvents) {
            if (event)
                event.emit([event.customEventData, ...values])
        }
    }

    static check_call_event(event: cc.Component.EventHandler) {
        var target = event.target;
        if (!cc.isValid(target))
            return false;

        event["_genCompIdIfNeeded"]();
        let compType = cc.js['_getClassById'](event["_componentId"]);

        let comp = target.getComponent(compType);
        if (!cc.isValid(comp))
            return false;

        let handler = comp[event.handler] as Function;
        if (typeof (handler) !== 'function')
            return false;

        if (handler.call(comp, event.customEventData))
            return true;
        return false;
    }

}

@ccclass(`ValueChangeCall`)
export class ValueChangeCall {
    @property({ displayName: `一直激活`, tooltip: '开启后会一直处于激活状态，否则触发一次后会自动关闭该事件' })
    valueTriggerMore: boolean = false;

    @property({ displayName: `过滤模式`, tooltip: '过滤模式，会根据条件过滤掉时间的触发', type: cc.Enum(FILTER_MODE) })
    ValueFilterMode: FILTER_MODE = FILTER_MODE.none;

    @property({ displayName: '判断值', visible(this: ValueChangeCall) { return this.ValueFilterMode !== FILTER_MODE.none } })
    valueCompare: string = '';

    @property({ displayName: '回调', type: [EventHandleCall] })
    valueChangeEvents: EventHandleCall[] = [];

    /**条件检查 */
    valueConditionCheck(a, b) {
        let cod = FILTER_MODE;
        switch (this.ValueFilterMode) {
            case cod.none: return true;
            case cod["=="]: return a == b;
            case cod["!="]: return a != b;
            case cod["<"]: return a < b;
            case cod[">"]: return a > b;
            case cod[">="]: return a >= b;
            case cod["<"]: return a < b;
            case cod["<="]: return a <= b;
            default: return false;
        }
    }
}


@ccclass
@executeInEditMode
@disallowMultiple
@menu('VM/VM-Base')
export default class VmBase extends cc.Component {

    //#region 基本属性 
    /***********多路径 *************************/
    @property({ displayName: `多路径`, tooltip: `是否启用模板多路径模式` })
    useMultipathMode: boolean = false;

    @property({ displayName: `路径`, visible(this: VmBase) { return !this.useMultipathMode; } })
    watchPath: string = '';

    @property({ displayName: `路径`, type: [cc.String], visible(this: VmBase) { return this.useMultipathMode; } })
    watchPathArr: string[] = [];

    /**储存模板多路径的值 */
    protected templateValueArr: any[] = [];

    /**监听数据对象 */
    _canWatchData = false;

    /*****双向监听,对组件的监听****** */
    @property({ displayName: `是否检查组件` })
    isCheckComponent = true;

    @property
    private _controller: boolean = false;
    get controller(): boolean { return this._controller; }
    @property({ displayName: `____双向监听`, tooltip: '激活controller,以开启双向绑定，否则只能接收消息', visible(this: VmBase) { return this.isCheckComponent } })
    set controller(value: boolean) {
        this._controller = value;
        value && this._checkEditorComponent();
    }

    @property({ displayName: `____组件名`, tooltip: '绑定组件的名字', visible(this: VmBase) { return this.isCheckComponent } })
    componentName: string = "";

    @property({ displayName: `____组件属性`, tooltip: '组件上需要监听的属性', visible(this: VmBase) { return this.isCheckComponent } })
    componentProperty: string = "";

    /**是否能监听组件的数据 */
    _canWatchComponent: boolean = false;

    /**监听的组件对象 */
    _watchComponent: cc.Component = null;

    /**组件代理者 */
    proxyOb: ProxyOb<cc.Component>;

    /**代理的实体组件 比如cc.Label,直接操控可以更改数据模型， 直接使用 proxy.string = xxx*/
    proxy: ProxyOb<cc.Component>['proxy'];

    //#endregion

    //#region 生命周期
    onLoad() {
        if (CC_EDITOR) {
            this.onEditor();
        } else {
            if (this.checkCanWatch()) {
                this.onValueInit();
            }
        }
    }
    start() { }

    onEditor() {
        //只在运行时检查组件是否缺失可用
        this._checkEditorComponent();
    }

    onDestroy() {
        this.onValueDestroy();
    }

    onEnable() {
        this.onValueEnable();
    }

    onDisable() {
        this.onValueDisEnable();
    }

    onRestore() {
        if (CC_EDITOR) {
            this._checkEditorComponent();
        }
    }
    //#endregion

    //#region 组件的监听
    /**检查是否可以监听组件 */
    checkCanWatch() {
        if (this.useMultipathMode) {
            this._canWatchData = !this.watchPathArr.some(path => path == "")
        } else {
            this._canWatchData = this.watchPath != '';
        }

        if (!this._canWatchData) {
            cc.warn(`节点${this.node.name}上VM组件没有填写完整监听数据的路径`);
            return false;
        }

        //解析路径
        this._parsePath();

        //绑定检查观察组件
        if (this.isCheckComponent) {
            this._watchComponent = this.node.getComponent(this.componentName);
            if (!this._watchComponent) { cc.warn(`节点${this.node.name}未设置需要监听的组件`); return false; }
            if (!this._watchComponent.enabled) return false;
            if (!this.componentProperty) { cc.warn(`节点${this.node.name}未设置需要监听的组件 的属性`); return false; }
            if (this.componentProperty in this._watchComponent === false) { cc.warn(`节点${this.node.name}需要监听的组件的属性${this.componentProperty}不存在`); return false; }
            this._bindComWatch();
            this._canWatchComponent = true;
        }
        return true;
    }

    /**挂在对应节点后，自动获取组件属性和名字, 会查找最排前符合的第一个组件 */
    private _checkEditorComponent() {
        for (let com of this.node[`_components`] as cc.Component[]) {
            let comName = com['__classname__'];
            let params = COMP_ARRAY_CHECK.find(arr => arr[0] == comName);
            if (params) {
                if (this.componentName == '')
                    this.componentName = params[0] as string;
                if (this.componentProperty == '')
                    this.componentProperty = params[1] as string;
                // if (params[2] !== null)
                //     this.controller = params[2] as boolean;
                return;
            }
        }
        this.componentName = this.componentProperty = '';
    }

    /**解析监听路径 */
    private _parsePath() {
        /**解析子路径 */
        let _parseTransChildPath = (paths: string[]) => {
            for (let i = 1; i < paths.length; i++) {
                let p = paths[i];
                //如果发现了路径使用了 * ，则自动去自己的父节点查找自己所在 index 值
                if (p == '*') {
                    let index = this.node.parent.children.findIndex(n => n === this.node);
                    if (index <= 0) index = 0;
                    paths[i] = index.toString();
                    break;
                }
            }
        };

        //提前拆分、并且解析路径
        let paths = this.watchPath.split('.');
        _parseTransChildPath(paths);

        //替换掉原路径
        this.watchPath = paths.join('.');

        //提前进行路径数组 的 解析
        let pathArr = this.watchPathArr;
        if (pathArr.length >= 1) {
            for (let i = 0; i < pathArr.length; i++) {
                let paths = pathArr[i].split('.');
                _parseTransChildPath(paths);
                this.watchPathArr[i] = paths.join('.');
            }
        }
        //打印出所有绑定的路径，方便调试信息
        if (CC_DEBUG) {
            cc.log('所有路径', this.watchPath ? [this.watchPath] : this.watchPathArr, '<<', this.node.getParent().name + '.' + this.node.name)
        }
        if (this.watchPath == '' && this.watchPathArr.join('') == '') {
            cc.log('可能未设置路径的节点:', this.node.getParent().name + '.' + this.node.name);
        }
    }

    /**设置多路径监听开启和关闭 */
    setMultPathEvent(enabled = true) {
        let setBind = (path: string) => {
            if (enabled) ProxyOb.bindPath('DataProxy_', path, this.onValueChanged, this);
            else ProxyOb.unBindPath('DataProxy_', path, this.onValueChanged, this);
        }
        if (this.useMultipathMode) {
            this.watchPathArr.forEach(path => setBind(path));
        } else if (this.watchPath != '') {
            setBind(this.watchPath);
        }
    }

    /**绑定组件监听代理 */
    _bindComWatch() {
        if (this.controller && this.isCheckComponent) {
            //注册组件监听，只监听一层
            let targetPath = this._watchComponent.uuid + this.componentProperty;
            this.proxyOb = new ProxyOb(this._watchComponent, targetPath, 'DataProxy_', false);
            this.proxyOb.proxyValueChangeCall = this.bindComPropertyChange.bind(this);
            this.proxy = this.proxyOb.proxy;
            // globalThis[`A`] = this.proxyOb;
        }
    }

    /**组件属性发生变动 */
    bindComPropertyChange(newValue: any, oldValue: any, key: string, receiver) {
        cc.director.emit('DataProxy_' + this.watchPath, newValue, oldValue, this.watchPath);
        let path = this.useMultipathMode ? this.watchPathArr : this.watchPath;
        this.onValueController(newValue, oldValue, path);
    }

    /**获取监听组件中指定的属性 */
    getComponentValue() {
        return this._watchComponent[this.componentProperty];
    }

    /**设置监听组件中指定的属性 */
    setComponentValue(value: any) {
        if (this._canWatchComponent)
            if (this.componentName == "cc.Toggle") {
                //如果遇到cc.Toggle 组件就调用上面的方法解决
                if (value) {
                    this.node.getComponent(cc.Toggle).check();
                }
                if (!value) {
                    this.node.getComponent(cc.Toggle).uncheck();
                }
            } else {
                this._watchComponent[this.componentProperty] = value;
            }
    }
    //#endregion


    //#region 快速修改值，button使用
    @property({ displayName: `设置handle调用限制`, tooltip: `按钮组件调用该组件的快速修改函数` })
    valueClamp: boolean = false;

    @property({ displayName: `_____限制模式`, type: cc.Enum(CLAMP_MODE), visible(this: VmBase) { return this.valueClamp } })
    valueClampMode: CLAMP_MODE = CLAMP_MODE.MIN_MAX;

    @property({ displayName: `_____最小值`, visible(this: VmBase) { return this.valueClamp && this.valueClampMode !== CLAMP_MODE.MAX } })
    valueMin: number = 0;

    @property({ displayName: `_____最大值`, visible(this: VmBase) { return this.valueClamp && this.valueClampMode !== CLAMP_MODE.MIN } })
    valueMax: number = 1;

    /**限制最终结果的取值范围 */
    private clampValue(res) {
        let min = this.valueMin;
        let max = this.valueMax;
        if (!this.valueClamp) return res;
        switch (this.valueClampMode) {
            case CLAMP_MODE.MIN_MAX:
                if (res > max) res = max;
                if (res < min) res = min;
                break;
            case CLAMP_MODE.MIN:
                if (res < min) res = min;
                break;
            case CLAMP_MODE.MAX:
                if (res > max) res = max;
                break;
            default:
                break;
        }
        return res;
    }

    /**快速添加值 */
    vAddInt(e, data) {
        this.vAdd(e, data, true);
    }

    vSubInt(e, data) {
        this.vSub(e, data, true);
    }

    vMulInt(e, data) {
        this.vMul(e, data, true);
    }

    vDivInt(e, data) {
        this.vDiv(e, data, true);
    }

    vAdd(e: cc.Event, data: any, int: boolean = false) {
        let a = parseFloat(data);
        let res = ProxyOb.getValue(this.watchPath, 0) + a;
        if (int) { res = Math.round(res) }
        ProxyOb.setValue(this.watchPath, this.clampValue(res));
    }

    vSub(e, data: any, int: boolean = false) {
        let a = parseFloat(data);
        let res = ProxyOb.getValue(this.watchPath, 0) - a;
        if (int) { res = Math.round(res) }
        ProxyOb.setValue(this.watchPath, this.clampValue(res));
    }

    vMul(e, data: any, int: boolean = false) {
        let a = parseFloat(data);
        let res = ProxyOb.getValue(this.watchPath, 0) * a;
        if (int) { res = Math.round(res) }
        ProxyOb.setValue(this.watchPath, this.clampValue(res));
    }

    vDiv(e, data: any, int: boolean = false) {
        let a = parseFloat(data);
        let res = ProxyOb.getValue(this.watchPath, 0) / a;
        if (int) { res = Math.round(res) }
        ProxyOb.setValue(this.watchPath, this.clampValue(res));
    }

    /**设置文本 */
    vString(e, data: any) {
        ProxyOb.setValue(this.watchPath, data);
    }

    /**设置整数 */
    vNumberInt(e, data: any) {
        this.vNumber(e, data, true);
    }

    /**设置数值 */
    vNumber(e, data: any, int: boolean = false) {
        let a = parseFloat(data);
        if (int) { a = Math.round(a) }
        ProxyOb.setValue(this.watchPath, this.clampValue(a));
    }
    //#endregion

    //#region  快速操作组件

    @property({ displayName: `快速功能` })
    fastEdit = false;

    @property({ displayName: `____查找列表`, type: [cc.Enum(FIND_LIST)], visible() { return this.fastEdit; } })
    findList: FIND_LIST[] = [];

    @property({ displayName: `____操作类型`, type: cc.Enum(ACTION_MODE), visible() { return this.fastEdit; } })
    actionType: ACTION_MODE = ACTION_MODE.查找组件;

    @property({ displayName: `____查找`, tooltip: '勾选后,会自动查找 find list 中填写的组件', visible() { return this.actionType === ACTION_MODE.查找组件 && this.fastEdit; } })
    get findTrigger() { return false; }
    set findTrigger(v: boolean) { this.setComponents(0); }

    @property({ displayName: `____激活`, tooltip: '勾选后,会批量激活 find list 中填写的组件', visible() { return this.actionType === ACTION_MODE.激活组件 && this.fastEdit; } })
    get enableTrigger() { return false; }
    set enableTrigger(v: boolean) { this.setComponents(1); }

    @property({ displayName: `____关闭`, tooltip: '勾选后,会批量关闭 find list 中填写的组件', visible() { return this.actionType === ACTION_MODE.激活组件 && this.fastEdit; } })
    get disableTrigger() { return false; }
    set disableTrigger(v: boolean) { this.setComponents(2); }

    @property({ displayName: `____允许删除`, tooltip: '允许删除节点的组件,确定需要移除请勾选,防止误操作', visible() { return this.actionType === ACTION_MODE.删除组件 && this.fastEdit; } })
    allowDelete: boolean = false;

    @property({ displayName: '____[ X DELETE X ]', tooltip: '勾选后,会批量删除 find list 中填写的组件', visible() { return this.allowDelete && this.actionType === ACTION_MODE.删除组件 && this.fastEdit; } })
    get deleteTrigger() { return false; }
    set deleteTrigger(v: boolean) { this.setComponents(3); }

    @property({ displayName: `____开头路径`, tooltip: '匹配的路径,匹配规则: 搜索开头为 game的路径', visible() { return this.actionType === ACTION_MODE.替换组件 && this.fastEdit; } })
    targetPath: string = 'game';

    @property({ displayName: `____替换路径`, tooltip: '替换的路径,将匹配到的路径替换', visible() { return this.actionType === ACTION_MODE.替换组件 && this.fastEdit; } })
    replacePath: string = '*';

    @property({ displayName: `____替换`, tooltip: '勾选后,会批量替换掉指定的路径', visible() { return this.actionType === ACTION_MODE.替换组件 && this.fastEdit; } })
    get replaceTrigger() { return false; }
    set replaceTrigger(v: boolean) { this.setComponents(4); }

    @property({ displayName: `____显示引用`, tooltip: '是否搜集绑定VM组件的节点?', visible() { return this.actionType === ACTION_MODE.查找组件 && this.fastEdit; } })
    canCollectNodes: boolean = false;

    @property({ displayName: `____查找到的引用`, type: [cc.Node], readonly: true, tooltip: '收集到绑定了VM组件相关的节点，可以自己跳转过去', visible() { return this.canCollectNodes && this.actionType === ACTION_MODE.查找组件 && this.fastEdit; } })
    collectNodes: cc.Node[] = [];

    /**设置组件 */
    setComponents(state: number) {
        let title = '搜索到当前节点下面的组件';
        switch (state) {
            case 0: title = '搜索到当前节点下面的组件'; break;
            case 1: title = '激活以下节点的组件'; break;
            case 2: title = '关闭以下节点的组件'; break;
            case 3: title = '删除以下节点的组件'; break;
            case 4: title = '替换以下节点的路径'; break;
            default: break;
        }
        cc.log(title)
        cc.log('______________________')
        this.findList.forEach(findEnum => this.searchComponent(FIND_LIST[findEnum], state));
        cc.log('______________________')
    }

    /**
     * 查找组件并设置
     * @param className 
     * @param state 0-查找节点组件 1-激活节点组件 2-关闭节点组件 3-移除节点组件
     */
    searchComponent(className: string, state: number = 0) {
        /**收集节点清空 */
        this.collectNodes = [];

        let comps = this.node.getComponentsInChildren(className) as VmBase[];
        if (comps == null || comps.length < 1) return;
        cc.log('[' + className + ']:');
        comps.forEach(v => {
            let ext = '';
            if (state <= 3) {
                //区分模板模式路径
                if (v.useMultipathMode && v.watchPathArr) {
                    ext = `  Path:[${v.watchPathArr.join(' | ')}]`;
                } else if (v.watchPath) {
                    ext = `  Path:[${v.watchPath}]`;
                }
            }
            cc.log(this.getNodePath(v.node) + ext);

            switch (state) {
                case 0:
                    if (this.canCollectNodes && this.collectNodes.indexOf(v.node) === -1) {
                        this.collectNodes.push(v.node);
                    }
                    break;
                case 1: v.enabled = true; break;
                case 2: v.enabled = false; break;
                case 3: v.node.removeComponent(v); break;
                case 4://替换指定路径
                    let targetPath = this.targetPath;
                    let replacePath = this.replacePath;
                    if (v.useMultipathMode) {
                        v.watchPathArr.forEach((path, i) => {
                            v.watchPathArr[i] = this._replaceNodePath(path, targetPath, replacePath);
                        });
                    } else {
                        v.watchPath = this._replaceNodePath(v.watchPath, targetPath, replacePath);
                    }
                default: break;
            }
        });
    }

    /**替换节点路径 */
    _replaceNodePath(path: string, search: string, replace: string) {
        let pathArr = path.split('.');
        let searchArr = search.split('.');
        let replaceArr = replace.split('.')
        let match = true;
        for (let i = 0; i < searchArr.length; i++) {
            if (pathArr[i] !== searchArr[i]) {
                //未匹配上
                match = false;
                break;
            }
        }
        //匹配成功准备替换路径
        if (match) {
            for (let i = 0; i < replaceArr.length; i++) {
                pathArr[i] = replaceArr[i];
            }
            cc.log(' 路径更新:', path, '>>>', pathArr.join('.'))
        }
        return pathArr.join('.');
    }

    /**查找节点路径 */
    getNodePath(parentNode: cc.Node) {
        let array = [];
        while (parentNode) {
            let p = parentNode.parent;
            if (p) {
                array.push(parentNode.name);
                parentNode = p;
            } else {
                break;
            }
        }
        return array.reverse().join('/');
    }
    //#endregion


    //#region 监听数值的回调
    @property({ displayName: `数值变动回调`, tooltip: `监听的数值模型发生变动` })
    isValueCall = false;

    @property({ displayName: `数值变动`, type: ValueChangeCall, visible() { return this.isValueCall } })
    valueChangeCall = new ValueChangeCall();

    @property({ displayName: `组件变动回调`, tooltip: `监听的组件数值发生变动`, visible(this: VmBase) { return this.isCheckComponent } })
    isComCall = false;

    @property({ displayName: `组件变动`, type: ValueChangeCall, visible() { return this.isComCall } })
    comChangeCall = new ValueChangeCall();

    //#endregion

    //#region  虚方法
    /**虚方法，脚本初始化调用 */
    protected onValueInit() {
        this.setComponentValue(ProxyOb.getValue(this.watchPath));
    }

    /**虚方法，值启用时调用 */
    protected onValueEnable() {
        if (!CC_EDITOR && this._canWatchData)
            this.setMultPathEvent(true);
    }

    /**虚方法，值禁用时调用 */
    protected onValueDisEnable() {
        if (!CC_EDITOR && this._canWatchData)
            this.setMultPathEvent(false);
    }

    /**虚方法，值销毁时调用 */
    protected onValueDestroy() {
    }

    /**虚方法，监听的数值改变后回调 */
    protected onValueChanged(newValue, oldValue, pathArr: string) {
        this.setComponentValue(newValue);

        //判断是否触发监听的回调
        if (this.isValueCall) {
            let change = this.valueChangeCall;
            if (!change.valueConditionCheck(newValue, change.valueCompare))
                return;
            change.valueChangeEvents.forEach(v => {
                v.call([newValue, oldValue, pathArr]);
            })
            //激活一次后，自动关闭组件
            this.isValueCall = !change.valueTriggerMore;
        }
    }

    /**[可重写]组件的值发生变化后，触发更新此值 */
    protected onValueController(newValue, oldValue, pathArr: string | string[]) {
        ProxyOb.setValue(this.watchPath, newValue);

        //判断是否触发监听的回调
        if (this.isComCall) {
            let change = this.comChangeCall;
            if (!change.valueConditionCheck(newValue, change.valueCompare))
                return;
            change.valueChangeEvents.forEach(v => {
                v.call([newValue, oldValue, pathArr]);
            })
            //激活一次后，自动关闭组件
            this.isComCall = !change.valueTriggerMore;
        }
    }

    //#endregion

}

/**
 * 数值格式化函数, 通过语义解析自动设置值的范围
 * 1:def(0)//显示一个默认值
 */
export class StringFormat {
    /**
     * 根据指定格式解析数值
     * @param value 值
     * @param format 格式
     * @returns 数值
     * @example
     *  组件实际使用 后面跟数字表示限制参数
     *  {{0:sep}}将数字按分号显示   100000-> 100,000 
     *  {{0:per2}} 将取值0~1 变成 1~100,可以指定修饰的小数位数  
     *  {{0:int}} 将取值变成整数 
     *  {{0:fix2}}数值转换为小数
     *  {{0:limit3}}字符串长度限制 
     *  使用{{1:int}} 表示替换组件绑定的路径中第一个的数据模型 并限制为int整数
     */
    static deal(value: number | string, format: string): string {
        if (format === '') return value as string;
        format = format.toLowerCase().trim();//不区分大小
        let match_func = format.match(/^[a-z|A-Z]+/gi);//匹配到 format 中的 函数名
        let match_num = format.match(/\d+$/gi);   //匹配到 format 中的参数
        let func: string = '';
        let num: number;
        let res: number | string = '';

        if (match_func) func = match_func[0];
        if (match_num) num = parseInt(match_num[0]);
        if (typeof value == 'number') {
            switch (func) {
                case 'int': res = this.int(value); break;
                case 'fix': res = this.fix(value, num); break;
                case 'kmbt': res = this.KMBT(value); break;
                case 'per': res = this.per(value, num); break;
                case 'sep': res = this.sep(value); break;
                default: break;
            }
        } else {
            switch (func) {
                case 'limit': res = this.limit(value, num); break;
                default: break;
            }
            // res = value;
        }
        return res as string;
    }

    /**[value:sep]将数字按分号显示 100000-> 100,000 */
    static sep(value: number) {
        let num = Math.round(value).toString();
        return num.replace(new RegExp('(\\d)(?=(\\d{3})+$)', 'ig'), "$1,");
    }

    /** [value:per2] 将取值0~1 变成 1~100,可以指定修饰的小数位数 */
    static per(value: number, fd: number) {
        return Math.round(value * 100).toFixed(fd);
    }

    /** [value:int] 将取值变成整数 */
    static int(value: number) {
        return Math.round(value);
    }

    /** [value:fix2]数值转换为小数*/
    static fix(value: number, fd: number) {
        return value.toFixed(fd)
    }

    /** [value:limit3]字符串长度限制 */
    static limit(value: string, count: number) {
        return value.substring(0, count);
    }

    /** [value:kmbt]将数字缩短显示为KMBT单位 大写,目前只支持英文 */
    static KMBT(value: number, lang: string = 'en') {
        //10^4=万, 10^8=亿,10^12=兆,10^16=京，
        let counts = [1000, 1000000, 1000000000, 1000000000000];
        let units = ['', 'K', 'M', 'B', 'T'];

        switch (lang) {
            case 'zh':
                //10^4=万, 10^8=亿,10^12=兆,10^16=京，
                counts = [10000, 100000000, 1000000000000, 10000000000000000];
                units = ['', '万', '亿', '兆', '京'];
                break;
            default:
                break;
        }
        return this.compressUnit(value, counts, units, 2);
    }

    //压缩任意单位的数字，后缀加上单位文字
    static compressUnit(value, counts: number[], units: string[], fixNum: number = 2): string {
        let res: string;
        let index = 0;
        for (; index < counts.length; index++) {
            if (value < counts[index]) {
                if (index > 0) {
                    res = (value / counts[index - 1]).toFixed(fixNum);
                } else {
                    res = value.toFixed(0);
                }
                break;
            }
        }
        return res + units[index];
    }

    //将数字按分显示 00:00 显示 （ms制）
    static time_m(value: number) {
        //todo
    }

    //将数字按秒显示 00:00:00 显示 （ms制）
    static time_s(value: number) {
        //todo
    }

    //将数字按 0:00:00:000 显示 （ms制）
    static time_ms(value: number) {
        //todo
    }

    //将时间戳显示为详细的内容
    static timeStamp(value: number) {
        //todo
        return new Date(value).toString()
    }

}


/** !! 修改的enum样式是个引用对象，一改，其他脚本也会更改 */
/**编辑面板属性刷新 */
/**获取观察数据的属性列表 */
// getWatchPropertyList() {
//     if (this.data)
//         this.dataKV = Object.keys(this.data);
//     let obj = {};
//     this.dataKV.forEach((v, i) => obj[v] = i + 1);
//     return obj;
// }

//     private _editorRefresh() {
//     let e = defaultEnum;
//     if (this.dataObj) {
//         //动态刷新替换enum属性
//         let v = this.dataObj.getWatchPropertyList();
//         if (v) {
//             v[`None`] = 0;
//             e = cc.Enum(v) as any;
//         }
//     }

    // cc.Class.Attr.setClassAttr(this, `watchObj`, `enumList`, cc.Enum.getList(e));
//     cc.Class.Attr.getClassAttrs(this)[`__proto__`][`_watchObj$_$enumList`] = cc.Enum.getList(e);
    // watchObj[`__proto__`][`constructor`][`__attrs__`][`watchProperty$_$enumList`] = cc.Enum.getList(e);
//     Editor.Utils.refreshSelectedInspector('node', this.node.uuid);
// }
